package com.xw.echo.core;

import com.alibaba.nacos.api.naming.pojo.Instance;
import com.xw.echo.core.factory.EchoElementFactory;
import com.xw.echo.core.nacos.NacosRegisterServer;
import com.xw.echo.core.protocol.HeartbeatRequest;
import com.xw.echo.core.protocol.HeartbeatResponse;
import com.xw.echo.core.protocol.MethodInvokData;
import com.xw.echo.core.protocol.Result;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class EchoServerProvider {

    //端口号
        private int port;
    private String serverIP;
    //Netty启动类
    private ServerBootstrap serverBootstrap;
    //连接线程组
    private NioEventLoopGroup bossGroup;
    //处理线程组
    private NioEventLoopGroup workerGroup;

    //handle线程组
    private EventLoopGroup handleGroup;
    //业务处理线程组
    private EventLoopGroup serviceGroup;

    private Map<String, Object> exposeBean;

    private NacosRegisterServer nacosRegisterServer = null;


    //服务是否启动
    private boolean isStarted = false;

    public EchoServerProvider(int port, Map<String, Object> exposeBean) {
        this.serverIP = getPublicIp();
        this.port = port;
        this.serverBootstrap = new ServerBootstrap();
        this.bossGroup = new NioEventLoopGroup();
        this.workerGroup = new NioEventLoopGroup();
        this.handleGroup = new DefaultEventLoopGroup(1);
        this.serviceGroup = new DefaultEventLoopGroup(100);
        this.exposeBean = exposeBean;
    }
    public static String getPublicIp() {
        String metadataUrl = "http://100.100.100.200/latest/meta-data/eipv4";
        try {
            URL url = new URL(metadataUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                StringBuilder response = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();
                return response.toString();
            } else {
                System.out.println("请求元数据服务失败，响应码: " + responseCode);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public void start() throws UnknownHostException {
        if (isStarted) {
            throw new IllegalStateException("服务已启动!");
        }
        // 配置服务器的NIO通道
        serverBootstrap.group(bossGroup, workerGroup) // 设置线程组
                .channel(NioServerSocketChannel.class) // 指定使用NIO类型的通道
                .option(ChannelOption.SO_BACKLOG, 1024) // 设置TCP backlog参数，控制未完成连接请求的最大数量
                .childOption(ChannelOption.TCP_NODELAY, true) // 设置TCP_NODELAY选项为true，禁用Nagle算法，减少网络延迟
                .childHandler(new EchoServerProviderInitailizar(handleGroup, serviceGroup, exposeBean)); // 设置通道初始化器
        // 绑定服务器到指定的IP地址和端口
        ChannelFuture channelFuture = serverBootstrap.bind(port);
        channelFuture.addListener(future -> {
            if (future.isSuccess()) {
                if (nacosRegisterServer != null) {
                    Instance serverInstance = nacosRegisterServer.getInstance();
                    if (serverInstance == null) {
                        serverInstance = new Instance();
                        serverInstance.setIp(serverIP);
                        serverInstance.setPort(port);
                    }
                    log.info("连接成功:{}",channelFuture.channel().localAddress());
                    nacosRegisterServer.register(serverInstance);
                }

                //监听关闭
                Channel channel = channelFuture.channel();

                ChannelFuture closeFuture = channel.closeFuture();
                closeFuture.addListener(future1 -> {
                    if (future1.isSuccess()) {
                        stopServer();
                        nacosRegisterServer.deregister();
                    }
                });
            }
        });

    }

    public void stopServer() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        handleGroup.shutdownGracefully();
        serviceGroup.shutdownGracefully();
    }

    public void setRegisterServer(NacosRegisterServer nacosRegisterServer) {
        this.nacosRegisterServer = nacosRegisterServer;
    }
}

class EchoServerProviderInitailizar extends ChannelInitializer<NioSocketChannel> {
    private final static Map<String, CompletableFuture<?>> futureMap = new ConcurrentHashMap<>();
    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);

    //Netty的编解码器 内置Handler通过这个线程组服务
    private EventLoopGroup eventLoopGroupHandler;
    private EventLoopGroup eventLoopGroupService;

    private Map<String, Object> exposeBean;

    public EchoServerProviderInitailizar(EventLoopGroup eventLoopGroupHandler, EventLoopGroup eventLoopGroupService, Map<String, Object> exposeBean) {
        this.eventLoopGroupHandler = eventLoopGroupHandler;
        this.eventLoopGroupService = eventLoopGroupService;
        this.exposeBean = exposeBean;
    }


    @Override
    protected void initChannel(NioSocketChannel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(eventLoopGroupHandler, new LengthFieldBasedFrameDecoder(1024, 3, 4, 0, 0));
        pipeline.addLast(eventLoopGroupHandler, new LoggingHandler());
        pipeline.addLast(eventLoopGroupHandler, EchoElementFactory.getCodec());
        pipeline.addLast(eventLoopGroupService, new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                if (msg instanceof MethodInvokData) {
                    MethodInvokData methodInvokData = (MethodInvokData) msg;
                    invokeMethod(methodInvokData, ctx);
                }
                if (msg instanceof HeartbeatRequest) {
                    ctx.writeAndFlush(new HeartbeatResponse());
                }
            }
        });

    }

    private void invokeMethod(MethodInvokData methodInvokData, ChannelHandlerContext ctx) throws NoSuchMethodException {

        // 1. 获取目标实例
        // 获取目标实例
        Object targetInstance = findTargetInstance(methodInvokData.getTargetInterface().getName());
        if (targetInstance == null) {
            // 向调用方返回异常结果
            Result errorResult = new Result();
            errorResult.setRequestId(methodInvokData.getRequestId());
            errorResult.setException(new RuntimeException("找不到目标实例：" + methodInvokData.getTargetInterface().getName()));
            ctx.writeAndFlush(errorResult);
            return;
        }

        // 获取目标方法
        Method method;
        try {
            method = targetInstance.getClass().getMethod(
                    methodInvokData.getMethodName(),
                    methodInvokData.getParameterTypes()
            );
        } catch (NoSuchMethodException e) {
            // 向调用方返回异常结果
            Result errorResult = new Result();
            errorResult.setRequestId(methodInvokData.getRequestId());
            errorResult.setException(e);
            ctx.writeAndFlush(errorResult);
            return;
        }

        // 提交到线程池执行
        threadPool.submit(() -> {
            Result result = new Result();
            result.setRequestId(methodInvokData.getRequestId());
            try {
                // 调用目标方法
                Object resultData = method.invoke(targetInstance, methodInvokData.getArgs());
                if (resultData instanceof CompletableFuture) {
                    // 如果返回值是 CompletableFuture，处理异步结果
                    CompletableFuture<?> future = (CompletableFuture<?>) resultData;
                    futureMap.put(methodInvokData.getRequestId(), future);
                    future.whenComplete((value, throwable) -> {
                        Result asyncResult = new Result();
                        asyncResult.setRequestId(methodInvokData.getRequestId());
                        if (throwable != null) {
                            asyncResult.setException((Exception) throwable);
                        } else {
                            asyncResult.setResultValue(value);
                        }
                        // 返回结果到调用方
                        ctx.writeAndFlush(asyncResult);
                    });
                } else {
                    // 如果返回值是普通对象
                    result.setResultValue(resultData);
                    ctx.writeAndFlush(result);
                }
            } catch (Exception e) {
                // 捕获并返回调用异常
                result.setException(e);
                ctx.writeAndFlush(result);
            }
        });


    }

    private Object resultProcess(String requestId, Object resultData) {
        Result result = new Result();
        if (resultData instanceof CompletableFuture) {
            futureMap.put(requestId, (CompletableFuture<?>) resultData);
            result.setResultValue(true);

        }
        return result;
    }


    private Object findTargetInstance(String targetInterfaceName) {
        return exposeBean.get(targetInterfaceName);
    }
}


